<html><head>
<title>HTML5:Texture + Perspective</title>
<script>
var
 time = new Date()
,fps = 0
,scene
,cnv
,ctx
,im
,x1 = 0, y1 = 0
,x2 = 320, y2 = 0
,x3 = 0, y3 = 240
,x4 = 320, y4 = 240,
 dx1 = 1, dy1 = -2,
 dx2 = -2, dy2 = 1,
 dx3 = 2, dy3 = -3,
 dx4 = -1, dy4 = -2;
var
 quality = 1/2
,angleOf = function(x,y) { // Calculate angle of vector
var
 a=[0,0,-2,-1,0,2,-3,4,2][(x<0?2:x?1:0)+(y<0?6:y?3:0)];
 return a<0?-a*Math.PI/2:a*Math.PI/2+(x?Math.atan(y/x):Math.PI/2);
}
function DrawImage(ctx, x1, y1, x2, y2, x3, y3, x4, y4, im, width, height) {
var
 xa = x1, ya = y1, xb = x2, yb = y2,
 dx1 = x3 - x1, dy1 = y3 - y1, dx2 = x4 - x2, dy2 = y4 - y2,
 le1 = Math.abs(dx1) > Math.abs(dy1) ? Math.abs(dx1) : Math.abs(dy1),
 le2 = Math.abs(dx2) > Math.abs(dy2) ? Math.abs(dx2) : Math.abs(dy2);
 le1 = (le1 > le2 ? le1 : le2) * quality;
 dx1 /= le1, dy1 /= le1, dx2 /= le1, dy2 /= le1;
 for(var i = 0; i < le1; ++ i) {
 var
  dx = xb - xa, dy = yb - ya,
  w = Math.pow(Math.pow(xb - xa, 2) + Math.pow(yb - ya, 2), 1 / 2);
  // a calculated by algorithm from book 1980's D.Grice with BASIC-samples
  a = [0, 0, -2, -1, 0, 2, -3, 4, 2][(dx < 0 ? 2 : dx ? 1 : 0) + (dy < 0 ? 6 : dy ? 3 : 0)];
  a = a < 0 ? -a * Math.PI / 2 : a * Math.PI / 2 + (dx ? Math.atan(dy / dx) : Math.PI / 2);
  if(0) {
   ctx.save(); ctx.translate(xa, ya); ctx.rotate(a);
   ctx.drawImage(im, 0, i / le1 * height, width, 2 / quality, 0, 0, w, 2 / quality);
   ctx.restore();
  } else {
   ctx.translate(xa, ya); ctx.rotate(a);
   ctx.drawImage(im, 0, i / le1 * height, width, 2 / quality, 0, 0, w, 2 / quality);
   ctx.rotate(-a); ctx.translate(-xa, -ya);
  }
  xa += dx1, ya += dy1, xb += dx2, yb += dy2;
 }
}

window.onload =
function(wnd) {
 im = document.getElementsByTagName("img")[0];
 cnv = document.getElementsByTagName("canvas")[0];
 ctx = cnv.getContext("2d");
 ctx.fillStyle = "#FF00FF";
 ctx.fillRect(0, 0, cnv.width, cnv.height);
 ctx.stroke();
 if(document.title.length > 27)
  setTimeout("location.href = 'http://www.gamedev.ru/pages/veros/'", 60000);
// setTimeout("location.href = location.href", 3000);
 setTimeout("Logo()", 1.250);
}
function Perspectives(vx1, vy1, vx2, vy2, vz, wx, wy, wz, points) {
var
 buf = [];
 dx1 = wx - vx1, dy1 = wy - vy1, dx2 = wx - vx2, dy2 = wy - vy2;
 for(var i in points) {
 var
  dz1 = wz - vz, dz2 = points[i].z - vz,
  x1 = vx1 + dx1 / dz1 * dz2,
  y1 = vy1 + dy1 / dz1 * dz2,
  x2 = vx2 + dx2 / dz1 * dz2,
  y2 = vy2 + dy2 / dz1 * dz2,
  dx = (points[i].x - vx1) / (vx2 - vx1),
  dy = (points[i].y - vy1) / (vy2 - vy1);
  buf.push({x: x1 + (x2 - x1) * dx, y: y1 + (x2 - x1) * dy, z: points[i].z});
 }
 return buf;
}
function Perspective(ctx, vx1, vy1, vx2, vy2, vz, wx, wy, wz, x, y, z) {
var
 dx1 = wx - vx1, dy1 = wy - vy1, dz1 = wz - vz,
 dx2 = wx - vx2, dy2 = wy - vy2, dz2 = z - vz,
 x1 = vx1 + dx1 / dz1 * dz2,
 y1 = vy1 + dy1 / dz1 * dz2,
 x2 = vx2 + dx2 / dz1 * dz2,
 y2 = vy2 + dy2 / dz1 * dz2,
 dx = (x - vx1) / (vx2 - vx1),
 dy = (y - vy1) / (vy2 - vy1),
 xx = x1 + (x2 - x1) * dx,
 yy = y1 + (x2 - x1) * dy;
 return {
  x: xx,
  y: yy
 }
}
var
 flags = {
  perspective: false
 },
 xp = 320, xd = -5, angleX = -60, angleY = -60, angleZ = 0, ii = 0,
 vx = 160, vy = 120, vz = 80, wz = -80, angleZ1 = 0;
function Draw3D(ctx, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, x, y, z, im, im1) {
var
 dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0, dx3 = 0, dy3 = 0, dx4 = 0, dy4 = 0,
 x0, y0, le,
 mtx1, mtx2, mtx3, mtx4,
 vx1 = 0, vy1 = 0, vx2 = 320, vy2 = 240, vz1 = vz, vz2 = wz, vcx = vx, vcy = vy;
 fi = z * Math.PI / 180.0;
 xx = Math.cos(fi); yy = Math.sin(fi);
 x0 = x1 * xx - y1 * yy; y1 = y1 * xx + x1 * yy; x1 = x0;
 x0 = x2 * xx - y2 * yy; y2 = y2 * xx + x2 * yy; x2 = x0;
 x0 = x3 * xx - y3 * yy; y3 = y3 * xx + x3 * yy; x3 = x0;
 x0 = x4 * xx - y4 * yy; y4 = y4 * xx + x4 * yy; x4 = x0;
 fi = y * Math.PI / 180.0;
 xx = Math.cos(fi); yy = Math.sin(fi);
 x0 = x1 * xx - z1 * yy; z1 = z1 * xx + x1 * yy; x1 = x0;
 x0 = x2 * xx - z2 * yy; z2 = z2 * xx + x2 * yy; x2 = x0;
 x0 = x3 * xx - z3 * yy; z3 = z3 * xx + x3 * yy; x3 = x0;
 x0 = x4 * xx - z4 * yy; z4 = z4 * xx + x4 * yy; x4 = x0;
 fi = x * Math.PI / 180.0;
 xx = Math.cos(fi); yy = Math.sin(fi);
 y0 = y1 * xx - z1 * yy; z1 = z1 * xx + y1 * yy; y1 = y0;
 y0 = y2 * xx - z2 * yy; z2 = z2 * xx + y2 * yy; y2 = y0;
 y0 = y3 * xx - z3 * yy; z3 = z3 * xx + y3 * yy; y3 = y0;
 y0 = y4 * xx - z4 * yy; z4 = z4 * xx + y4 * yy; y4 = y0;
 le = Math.abs(x1) > Math.abs(y1) ? (x1) : (y1);
 x1 += 160, y1 += 120;
 x2 += 160, y2 += 120;
 x3 += 160, y3 += 120;
 x4 += 160, y4 += 120;
 if(flags.perspective) {
  mtx1 = Perspective(ctx,vx1, vy1, vx2, vy2, vz1, vcx, vcy, vz2, x1, y1 ,z1);
  mtx2 = Perspective(ctx,vx1, vy1, vx2, vy2, vz1, vcx, vcy, vz2, x2, y2 ,z2);
  mtx3 = Perspective(ctx,vx1, vy1, vx2, vy2, vz1, vcx, vcy, vz2, x3, y3 ,z3);
  mtx4 = Perspective(ctx,vx1, vy1, vx2, vy2, vz1, vcx, vcy, vz2, x4, y4 ,z4);
  x1 = mtx1.x; y1 = mtx1.y;
  x2 = mtx2.x; y2 = mtx2.y;
  x3 = mtx3.x; y3 = mtx3.y;
  x4 = mtx4.x; y4 = mtx4.y;
 }
 // Summ-algorythm calculated by algolist.ru
 if((x2 + x1) * (y2 - y1) + (x4 + x2) * (y4 - y2)
  + (x3 + x4) * (y3 - y4) + (x1 + x3) * (y1 - y3) < 0)
  scene.unshift(
   {x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3, x4: x4, y4: y4, opac: im1 ? .5 : .5, image: im1 ? im1 : im}
  );
 else
  scene.push(
   {x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3, x4: x4, y4: y4, opac: 1, image: im}
  );
}
function Logo() {
 ctx.globalAlpha = 1;
 ctx.fillStyle = "#0000FF";
 ctx.beginPath();
 ctx.fillRect(0, 0, cnv.width, cnv.height);
 ctx.lineWidth = 1.0;
 scene = [];
 house = document.getElementsByTagName("img")[1];
// house = im;
 x1 = -64; y1 = -64; z1 = -64; x2 = -64; y2 = -64; z2 = +64;
 x3 = -64; y3 = +64; z3 = -64; x4 = -64; y4 = +64; z4 = +64;
 Draw3D(ctx, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, angleX, angleY, angleZ, im, house);
 x1 = +64; y1 = -64; z1 = +64; x2 = -64; y2 = -64; z2 = +64;
 x3 = +64; y3 = -64; z3 = -64; x4 = -64; y4 = -64; z4 = -64;
 Draw3D(ctx, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, angleX, angleY, angleZ, im, house);
 x1 = -64; y1 = +64; z1 = +64; x2 = -64; y2 = -64; z2 = +64;
 x3 = +64; y3 = +64; z3 = +64; x4 = +64; y4 = -64; z4 = +64;
 Draw3D(ctx, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, angleX, angleY, angleZ, im, house);
 for(var i in scene) {
  ctx.globalAlpha = scene[i].opac;
  DrawImage(ctx, scene[i].x1, scene[i].y1, scene[i].x2, scene[i].y2, scene[i].x3, scene[i].y3, scene[i].x4, scene[i].y4, scene[i].image, scene[i].image.width, scene[i].image.height);
 }
 ii ++;
 angleX += .25;
 angleY += 1.36;
 angleZ += .05;
// vx = 160 + 50 * Math.cos(angleZ1), vy = 120 + 50 * Math.sin(angleZ1);
 angleZ1 += Math.PI / 180 * 5;
 newTime = new Date();
 if(newTime.getSeconds() == time.getSeconds())
  fps ++;
 else
  time = newTime, window.status = fps, fps = 0;
 setTimeout("Logo()", 25/25);
}
</script>
<style>
label > input { display: none; }
label > input ~ span { border: gray thick outset; }
label > input:checked ~ span { border: gray thick inset; }
</style></head>
<body>
<canvas width='320px' height='240px'></canvas><hr/>
<label for='perspective'>
<input id='perspective' type=checkbox onchange='flags.perspective = this.checked' checked />
<span>Perspective</span>
</label><br/>
<input type=range min='-499' max='499' value='40' onchange='vz=this.value' /><br/>
<input type=range min='-499' max='499' value='-40' onchange='wz=this.value' /><br/>
<img src='http://www.gstatic.com/codesite/ph/images/defaultlogo.png'></img>
<img src='http://javascript.ru/forum/images/ca_serenity/misc/logo.gif'></img>
</body>